<?php

declare(strict_types=1);

namespace app\common\service\sys;

use app\common\traits\ServiceTrait;
use app\common\dao\sys\FilesDao;
use think\facade\Filesystem;


/**
 * 上传文件管理表
 * @author:kaige
 * @update:2022-06-12
 * @copyright ©2022 泉州市盛筑信息科技有限公司 版权所有
 */
class FilesService
{
  protected $dao = null;

  public function __construct()
  {
    $this->dao = new FilesDao();
  }
  use ServiceTrait;

  /**
   * 重写 关联with ，model必须存在with里的方法
   */
  public function _list_with()
  {
    return ['glgroup', 'glcompany', 'gluser'];
  }

  /**
   * 重写 要显示关联表的字段
   */
  public function _list_visible()
  {
    return [
      'glgroup' => ['id', 'name'],
      'glcompany' => ['id', 'name'],
      'gluser' => ['id', 'real_name']
    ];
  }

  /**
   * 重写 列表过滤条件
   */
  public function _list_where($post)
  {
    $where = [];
    if (isset($post['search_name']) && $post['search_name'] != "") {
      $where[] = ['name', 'like', '%' . $post['search_name'] . '%'];
    }
    if (isset($post['keywords']) && $post['keywords'] != "") {
      $where[] = ['name', 'like', '%' . $post['keywords'] . '%'];
    }
    if (isset($post['search_id']) && $post['search_id'] != "") {
      $where[] = ['id', '=', $post['search_id']];
    }
    if (isset($post['group_id']) && $post['group_id'] != "") {
      $where[] = ['group_id', '=', $post['group_id']];
    }
    //过滤权限
    if (isset($post['user_id']) && !empty($post['user_id'])) {
      $rs = new \app\common\service\sys\RoleService();
      $arrwh = $rs->getRoleDataAuth($post['user_id'], 'handle_uid');
      $where = array_merge_recursive($where, $arrwh);
    }
    $result['where'] = $where;
    $result['field'] = ['*'];
    $result['order'] = ['create_time' => 'desc'];
    return $result;
  }

  /**
   * 重写 列表数据格式化
   */
  public function _list_format($list)
  {
    foreach ($list as $k => &$v) {
      if (isset($v['file_ext'])) {
        $list[$k]['type'] = $this->fileJsType($v['file_ext']);
      }
    }
    return $list;
  }

  /**
   * 文件类型，给前端js的 type=1 非图片，2=图片 
   */
  protected function fileJsType($ext)
  {
    if ($this->imgVideoDoc($ext) == 4) {
      return 2;
    }
    return 1;
  }

  /**
   * 自动辩别文件类型分配分组ID
   */
  protected function imgVideoDoc($ext)
  {
    if (strpos('jpg,png,gif,bmp,ico', $ext) !== false) {
      //图片 4
      return 4;
    } elseif (strpos('avi,mp3,mp4,wav', $ext) !== false) {
      //音视频 2
      return 2;
    } elseif (strpos('zip,txt,doc,xls,xlsx,ppt,pptx,pdf', $ext) !== false) {
      //文档 1
      return 1;
    } else {
      return 7;
    }
  }

  /**
   * 获取文件信息
   */
  public function getFileInfo($id = '')
  {
    $data = $this->dao->getInfoById($id);
    if ($data) {
      $data = $data->toArray();
      $data['type'] = $this->fileJsType($data['file_ext']);
      return $data;
    }
    return [];
  }

  /**
   * 获取文件URL - 接口
   */
  public function getUrlById($id = '')
  {
    return $this->dao->getUrlById($id);
  }

  /**
   * 物理删除文件
   * @param $id 可批量
   * @return array
   */
  public function delFiles($id)
  {
    if (!empty($id)) {
      //批量删除
      $ids = explode(',', $id);
      $info = $this->dao->getListAll([['id', 'IN', $ids]]);
      $file_del = [];
      $no_del = [];
      $new_ids = [];
      //先删除物理文件
      if (!empty($info)) {
        foreach ($info as $vo) {
          //使用次数
          if ($vo['use_count'] < 1) {
            $new_ids[] = $vo['id'];
            //取物理地址
            $fpath = $vo['path'];
            $fpath = app()->getRootPath() . 'public' . $fpath; //存数据库时的绝对路径取消，少存点数据，本地存储可以这样。
            $fpath = str_replace('\\', DIRECTORY_SEPARATOR, $fpath);
            $file_del[$vo['id']]['id'] = $vo['id'];
            $file_del[$vo['id']]['path'] = $fpath;
            if (file_exists($fpath)) {
              //删除文件
              $file_del[$vo['id']]['isdel'] = unlink($fpath);
            }
          } else {
            $no_del[] = $vo['id'];
          }
        }
      }
      if (!empty($new_ids)) {
        //根据主键物理删除-记录
        $dres = $this->dao->multiDelete($new_ids);
        if ($dres) {
          return _ok(1025, ['isdel' => $file_del, 'nodel' => $no_del]);
        }
      }
      return _err(1026, ['isdel' => $file_del, 'nodel' => $no_del]);
    }
    return _err(1026);
  }

  /**
   * 返回图片地址
   * @param string $id
   * @return array|mixed|string
   */
  public function getFilesUrl($id = '')
  {
    //空就输出数据库里的默认
    if (empty($id)) {
      $id = _conf('default_image'); //配置里默认图片--数据库里的
    }
    //如果还为空，输出系统默认的
    if (empty($id)) {
      return config('kaige.default_image'); //系统默认图片
    }

    if (stripos($id, 'http') !== false || stripos($id, 'https') !== false) {
      return $id;
    }

    $image = $this->dao->getUrlByIdCache($id);
    if ($image) {
      if (stripos($image, 'http') !== false || stripos($image, 'https') !== false) {
        return str_replace("\\", "/", $image);
      } else {
        return config('kaige.domain_name') . $image;
      }
    }
    return config('kaige.default_image'); //默认图片
  }

  /**
   * 使用次数变更
   * @param $id
   * @param $num 默认加次数
   * @return bool
   */
  public function useCount($id, $num = 1)
  {
    return $this->dao->useCount($id, $num);
  }

  /**
   * 上传文件(支持批量)  集文档、图片、视频
   * @param $files 文件(可以是多个，数组形式)
   * @param $uid 上传用户id
   * @param $other 其它[分组，浏览器，单位，input_name] 更多的用数组传递，便于扩展
   * @return array
   * 注：前端多文件上传可能是通过js遍历，每次上传一个
   */
  public function upfiles($files, $uid, $other)
  {
    $maxsize      = config('kaige.file_max_size');
    $file_ext     = config('kaige.file_ext');
    $file_mime    = config('kaige.file_mime');
    $rpath        = config('filesystem.disks.public.url');
    $file_domain  = config('kaige.file_domain');
    $kai_url      = config('kaige.kai_url');
    //验证规则
    $rule = 'filesize:' . $maxsize . '|fileExt:' . $file_ext . '|fileMime:' . $file_mime;
    try {
      $files_arr = [];
      $files_isadd = 0; //新增的
      $files_err = []; // 失败的信息
      $files_isexist = 0; //已存在的
      if (count($files) > 5) {
        return _err('每次最多同时上传5个文件');
      };
      //取用户信息
      $compay_id = (new UserService())->getCompanyIdByUserId($uid);
      if (empty($other['company_id'])) {
        $other['company_id'] = $compay_id;
      }
      foreach ($files as $file) {
        $file_up_name = $file->getOriginalName();
        if ($file->getSize() > $maxsize) {
          $files_err[] = $file_up_name . '，文件超出' . floor($maxsize / 1048576) . 'MB';
          continue;
        }
        // 验证
        validate([$other['key_name'] => $rule])->check($files);
        // 查重
        $hash = $file->hash('sha1');
        $hash_result = $this->dao->get_hash_file($hash);
        if ($hash_result) {
          $files_arr[] = $hash_result; //已存在的 直接输出信息
          $files_isexist++;
        } else {
          // 数据收集
          $in_data = [
            'id' => create_guid(),
            'hash' => $hash,
            'file_type' => $file->getOriginalMime(),
            'group_id' => ($other['group_id'] == 7 ? $this->imgVideoDoc($file->getOriginalExtension()) : $other['group_id']),
            'name' => $file_up_name,
            'file_ext' => $file->getOriginalExtension(),
            'file_size' => $file->getSize(),
            'file_size_cn' => files_size_format($file->getSize()),
            'storage_engine' => 1,
            'ip' => _gip(),
            'use_count' => 0, //默认使用次数为0
            'company_id' => $other['company_id'],
            'browser' => $other['browser'],
            'handle_uid' => $uid
          ];
          // 自动辩别文件类型分配到分组里

          // 上传文件
          $f_name = Filesystem::disk('public')->putFile($other['key_name'], $file);
          $f_path = $rpath . DIRECTORY_SEPARATOR . $f_name;
          // 斜扛处理
          $f_path = str_replace('\\', '/', $f_path);
          // 是否加上域名
          $f_url = $file_domain === true ? $kai_url . $f_path : $f_path;
          // 数据继续收集
          $in_data['url'] = $f_url;
          $in_data['path'] =  $f_path;
          // 保存
          $inSave = $this->dao->add($in_data);
          if ($inSave) {
            $files_arr[] = [
              'id' => $inSave->id,
              'url' => $inSave->url,
              'name' => $inSave->getAttr('name'),
              'ext' => $inSave->file_ext,
              'type' => $this->fileJsType($inSave->file_ext),
              'file_size' => $inSave->file_size,
              'hash' => $inSave->hash
            ];
            $files_isadd++;
          } else {
            $files_err[] = $file_up_name . '上传失败';
          }
        }
      }
      return _ok('上传成功', ['files' => $files_arr, 'ok' => $files_isadd, 'err' => $files_err, 'exist' => $files_isexist]);
    } catch (\think\exception\ValidateException $e) {
      return _err($e->getMessage());
    }
  }

  /**
   * 移入分组
   */
  public function moveGroup($data)
  {
    if (empty($data['files_ids'])) {
      return _err(1002);
    }
    if (isset($data['group_id']) && $data['group_id'] == '') {
      return _err(1002);
    }
    $res = $this->dao->multiUpdate($data['files_ids'], ['group_id' => $data['group_id']]);
    if ($res) return _ok(1021);
    return _err(1022);
  }
}
